﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;

namespace Weka
{
    public class Serliser
    {
        private Dictionary<Type, ObjectSerialiserProvider> _cachedTypeSerlisers = new Dictionary<Type, ObjectSerialiserProvider>(0);

        public byte[] ToData<T>(T value)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                ToData<T>(value, ms);
                return ms.ToArray();
            }
        }

        public void ToData<T>(T value, Stream stream)
        {
            ToData<T>(value, new StreamWrita(stream));
        }

        internal void ToData<T>(T value, StreamWrita streamWriter)
        {
            GetTypeSerliser<T>().ToData(value, streamWriter);
        }

        private ObjectSerialiser<T> GetTypeSerliser<T>()
        {
            return GetHCreator<T>().Create();
        }
        internal ObjectSerialiserProvider<T> GetHCreator<T>()
        {
            ObjectSerialiserProvider osp;
            if (!_cachedTypeSerlisers.TryGetValue(typeof(T), out osp))
            {
                var cachedTypeSerlisers = new Dictionary<Type, ObjectSerialiserProvider>(_cachedTypeSerlisers);
                if (!cachedTypeSerlisers.TryGetValue(typeof(T), out osp))
                {
                    osp = new ObjectSerialiserProvider<T>(cachedTypeSerlisers);
                    cachedTypeSerlisers[typeof(T)] = osp;
                    Interlocked.Exchange(ref _cachedTypeSerlisers, cachedTypeSerlisers);
                }
            }
            return ((ObjectSerialiserProvider<T>)osp);
        }

        internal static ObjectSerialiserProvider<T> GetHCreator<T>(Dictionary<Type, ObjectSerialiserProvider> cachedTypeSerlisers)
        {
            ObjectSerialiserProvider osp;
            
            if (!cachedTypeSerlisers.TryGetValue(typeof(T), out osp))
                cachedTypeSerlisers[typeof(T)] = osp = new ObjectSerialiserProvider<T>(cachedTypeSerlisers);

            return ((ObjectSerialiserProvider<T>)osp);
        }
    }
}
